from datetime import date
from django.shortcuts import render_to_response, redirect
from google.appengine.ext.db import Key
from .decorators import requires_google_admin_login
from .models import PromoCode, Trip, TripOrder, TripSignupInfo, TripSpot
from .forms import TripForm, TripSpotForm, TripSignupForm
from django.http import HttpResponse
import csv
import re
from django.conf import settings
from django.views.generic.simple import direct_to_template
from django.views.generic.create_update import update_object
from django.core.urlresolvers import reverse
#from django.db.models import get_model
from django.db.models.loading import get_model

##############################################
# Generic method to update (not add) any object
##############################################
def generic_object_update(request, object_class, object_id, form_class, template_form, success_redir=None):
    object_name = object_class.__name__
    o = object_class.get( Key.from_path(object_name, int(object_id)) )

    if request.method == 'GET':
        form = form_class(instance=o)
    elif request.method == 'POST':
        form = form_class(data=request.POST or None, instance=o)
        if form.is_valid():
            o = form.save(commit=False)
            o.put()
            if success_redir is not None:
                return redirect(success_redir)
    return render_to_response(template_form, {'form': form, 'object_id': object_id})

##############################################
# Generic direct to template view for admin
# http://docs.djangoproject.com/en/dev/topics/auth/#limiting-access-to-generic-views
##############################################
@requires_google_admin_login
def admin_direct_to_template(*args, **kwargs):
    return direct_to_template(*args, **kwargs)

##############################################
# Generic method for an admin to view any object
##############################################
@requires_google_admin_login
def admin_generic_object_view(request, object_class, object_id, template):
    object_name = object_class.__name__
    obj = object_class.get( Key.from_path(object_name, int(object_id)) )
    return render_to_response(template, {'obj': obj})

##############################################
# Admin page to list trips
##############################################
@requires_google_admin_login
def admin_trip_list(request):
    trips = Trip.all()    
    return render_to_response('tripsignup/admin_trip_list.html', {'trips': trips})

##############################################
# Admin page to update or add a trip
##############################################
@requires_google_admin_login
def admin_trip_add_update(request, trip_id=None):
    trip = None
    if trip_id:
        trip = Trip.get( Key.from_path('Trip', int(trip_id)) )

    if request.method == 'GET':
        form = TripForm(instance=trip)
    elif request.method == 'POST':
        form = TripForm(data=request.POST or None, instance=trip)
        if form.is_valid():
            trip = form.save(commit=False)
            trip.put()
            return redirect('/admin/trip/list/') 
    return render_to_response('tripsignup/admin_trip_add_update.html', {'form': form, 'trip_id': trip_id})

##############################################
# Admin page to view TripSpot records
##############################################
@requires_google_admin_login
def admin_tripspot_list(request, year=None, trip_number=None):
    if trip_number is not None:
        trip_number = int(trip_number)
    if request.method == 'POST':
        return redirect('admin_tripspot_list', year=request.POST['year'], trip_number=request.POST['trip_number'])
    years = set()
    trip_nums = set()

    trips = Trip.all()
    for trip in trips:
        years.add(trip.ski_season)
        trip_nums.add(trip.trip_number)

    trip_spots = None
    if year is not None and trip_number is not None:
        trip_spots = TripSpot.all().filter('ski_season = ', year).filter('trip_number = ', trip_number)#.order('date_created')
    return render_to_response('tripsignup/admin_tripspot_list.html', { 'trip_spots': trip_spots,
                                                                       'years' : years,
								       'year': year,
								       'trip_nums': trip_nums,
								       'trip_number': trip_number,
								     })

##############################################
# Admin signup CSV download
##############################################
def admin_trip_roster_download(request, year, trip_number):
    response = HttpResponse(mimetype='text/csv')
    response['Content-Disposition'] = 'attachment; filename=roster-%s-%s.csv' % (year, trip_number)
    writer = csv.writer(response, quoting=csv.QUOTE_ALL)

    signup_headers = []
    spot_headers = []
    order_headers = []
    for p in TripSignupInfo.properties():
        signup_headers.append(p)
    for p in TripSpot.properties():
        spot_headers.append(p)
    for p in TripOrder.properties():
        order_headers.append(p)
    writer.writerow(['#']+signup_headers+spot_headers+order_headers)

    trip_spots = TripSpot.all().filter('ski_season = ', year).filter('trip_number = ', int(trip_number))
    i = 0
    for trip_spot in trip_spots:
        row = [i]
        i += 1
        for f in signup_headers:
            row.append(getattr(trip_spot.trip_signup_info, f))
        for f in spot_headers:
            row.append(getattr(trip_spot, f))
        for f in order_headers:
            row.append(getattr(trip_spot.trip_order, f))
        writer.writerow(row)


    return response 
     



##############################################
# Admin page to update trip spots								    
##############################################
@requires_google_admin_login
def admin_tripspot_update_old(request, tripspot_id):
    tripspot = TripSpot.get( Key.from_path('TripSpot', int(tripspot_id)) )

    if request.method == 'GET':
        form = TripSpotForm(instance=tripspot)
    elif request.method == 'POST':
        form = TripSpotForm(data=request.POST or None, instance=tripspot)
        if form.is_valid():
            trip = form.save(commit=False)
            trip.put()
    return render_to_response('tripsignup/admin_tripspot_update.html', {'form': form, 'tripspot_id': tripspot_id})

@requires_google_admin_login
def admin_tripspot_update(request, tripspot_id):
    tripspot = TripSpot.get( Key.from_path('TripSpot', int(tripspot_id)) )
    url = reverse('admin_tripspot_view', args=[tripspot_id])
    return generic_object_update(request, TripSpot, tripspot_id, TripSpotForm, 'tripsignup/admin_tripspot_update.html', success_redir=url)

##############################################
# Admin to update a trip order
##############################################
@requires_google_admin_login
def admin_triporder_update(request, triporder_id):
    triporder = TripOrder.get( Key.from_path('TripOrder', int(tripspot_id)) )
    url = reverse('admin_triporder_view', args=[triporder_id])
    return generic_object_update(request, TripOrder, triporder_id, TripOrderForm, 'tripsignup/admin_triporder_update.html', success_redir=url)

##############################################
# Select a trip
##############################################
def trips_select(request):
    if request.method == 'GET':
        trips = Trip.all().filter('start_date >', date.today()).order('start_date').order('trip_number')
    if request.method == 'POST':
        if request.POST.has_key('member_discount'):
            url = '/signup/discount/%s/'
        else:
            url = '/signup/%s/'
        return redirect(url % ( ','.join( [key for key in request.POST.keys() if re.match('[0-9]+', key)] )))

    return render_to_response('tripsignup/trips_select.html', {'trips': trips})

##############################################
# Thank you message after payment
##############################################
def payment_thanks(request):
    return render_to_response('tripsignup/payment_thanks.html', {})

##############################################
# Show and preview the trip sign up form
##############################################
def trips_signup(request, tripids, has_discount=False):
    if has_discount:
        discount = float(20)
    else:
        discount = float(0)

    form = TripSignupForm(data=request.POST or None)
    # create a list of trip ids as integers
    triplist = [int(tripid) for tripid in tripids.split(',')]
   
    #if request.method == 'GET': 
    # make sure that all of the trips in the list exist
    triplist_errors = Trip.validate_ids_for_signup(triplist) 
    if len(triplist_errors) > 0:
        return redirect('/?message=%s' % (triplist_errors[0]))

    trips = Trip.get_by_id(triplist)
    total_cost = sum([trip.price for trip in trips]) - discount

    if request.method == 'POST':
        if form.is_valid():
            # TODO: wrap these three saves in a transaction
            # save the order info
            trip_order = TripOrder(billing_first_name=form.cleaned_data['billing_first_name'],
                                   billing_last_name=form.cleaned_data['billing_last_name'],
                                   billing_email = form.cleaned_data['billing_email'],
                                   pay_method = form.cleaned_data['pay_method'],
                                   total = float(total_cost),
                                   paid  = float(0),
                                   trip_list = triplist
            )
            trip_order.put()
            # save the signup info 
            trip_signup_info = form.save(commit=False)
            trip_signup_info.put()

            trip_numbers = []
            trip_years   = []
            for trip in trips:
                trip_spot = TripSpot(trip_order=trip_order,
                                     trip_signup_info=trip_signup_info,
                                     trip_number=trip.trip_number,
                                     ski_season=trip.ski_season) 
                trip_spot.put()

                #build the list of trip numbers and years
                if not trip.trip_number in trip_numbers:
                    trip_numbers.append(str(trip.trip_number))
                if not trip.ski_season in trip_years:
                    trip_years.append(trip.ski_season)
            #description of the order
            trips_desc = 'Weekend Ski Trips %s for %s' % (','.join(trip_numbers), ','.join(trip_years))
            return render_to_response('tripsignup/trips_confirmed.html', {'trips': trips, 
                                                                          'total_cost': total_cost, 
                                                                          'discount': discount,
                                                                          'has_discount': has_discount,
                                                                          'address': settings.POSTAL_ADDRESS,
                                                                          'waiver_url': settings.WAIVER_URL,
                                                                          'form': form, 
                                                                          'trips_desc': trips_desc,
                                                                          'trip_order':trip_order})
            
         
    
    return render_to_response('tripsignup/trips_signup.html', {'trips': trips,
                                                               'total_cost': total_cost, 
                                                               'discount': discount,
                                                               'has_discount': has_discount,
                                                               'form': form})
